home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / JSlider.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  34.2 KB  |  1,169 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)JSlider.java    1.77 98/08/28
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package javax.swing;
  16.  
  17. import javax.swing.border.*;
  18. import javax.swing.event.*;
  19. import javax.swing.plaf.*;
  20. import javax.accessibility.*;
  21.  
  22. import java.io.Serializable;
  23. import java.io.ObjectOutputStream;
  24. import java.io.ObjectInputStream;
  25. import java.io.IOException;
  26.  
  27. import java.util.*;
  28. import java.beans.*;
  29.  
  30.  
  31. /**
  32.  * A component that lets the user graphically select a value by slding
  33.  * a knob within a bounded interval. The slider can show both 
  34.  * major tick marks and minor tick marks between them. The number of
  35.  * values between the tick marks is controlled with 
  36.  * <code>setMajorTickSpacing</code> and <code>setMinorTickSpacing</code>. 
  37.  * <p>
  38.  * For the keyboard keys used by this component in the standard Look and
  39.  * Feel (L&F) renditions, see the
  40.  * <a href="doc-files/Key-Index.html#JSlider">JSlider</a> key assignments.
  41.  * <p>
  42.  * <strong>Warning:</strong>
  43.  * Serialized objects of this class will not be compatible with
  44.  * future Swing releases.  The current serialization support is appropriate
  45.  * for short term storage or RMI between applications running the same
  46.  * version of Swing.  A future release of Swing will provide support for
  47.  * long term persistence.
  48.  *
  49.  * @beaninfo
  50.  *      attribute: isContainer false
  51.  *    description: A component that supports selecting a integer value from a range.
  52.  * 
  53.  * @version 1.77 08/28/98
  54.  * @author David Kloba
  55.  */
  56. public class JSlider extends JComponent implements SwingConstants, Accessible
  57. {
  58.     /**
  59.      * @see #getUIClassID
  60.      * @see #readObject
  61.      */
  62.     private static final String uiClassID = "SliderUI";
  63.  
  64.     private boolean paintTicks = false;
  65.     private boolean paintTrack = true;
  66.     private boolean paintLabels = false;
  67.     private boolean isInverted = false;
  68.  
  69.     /**
  70.      * The data model that handles the numeric maximum value,
  71.      * minimum value, and current-position value for the slider.
  72.      */
  73.     protected BoundedRangeModel sliderModel;
  74.  
  75.     /**
  76.      * The number of values between the major tick marks -- the 
  77.      * larger marks that break up the minor tick marks.
  78.      */
  79.     protected int majorTickSpacing;
  80.  
  81.     /**
  82.      * The number of values between the minor tick marks -- the 
  83.      * smaller marks that occur between the major tick marks.
  84.      * @see #setMinorTickSpacing
  85.      */
  86.     protected int minorTickSpacing;
  87.  
  88.     /**
  89.      * If true, the knob (and the data value it represents) 
  90.      * resolve to the closest tick mark next to where the user
  91.      * positioned the knob.
  92.      * @see #setSnapToTicks
  93.      */
  94.     protected boolean snapToTicks = false;
  95.  
  96.     /**
  97.      * If true, the knob (and the data value it represents) 
  98.      * resolve to the closest slider value next to where the user
  99.      * positioned the knob.
  100.      * @see #setSnapToValue
  101.      */
  102.     boolean snapToValue = true;
  103.  
  104.     /**
  105.      * @see #setOrientation
  106.      */
  107.     protected int orientation;
  108.  
  109.  
  110.     /**
  111.      */
  112.     private Dictionary labelTable;
  113.     
  114.  
  115.     /**
  116.      * The changeListener (no suffix) is the listener we add to the
  117.      * Sliders model.  By default this listener just forwards events
  118.      * to ChangeListeners (if any) added directly to the slider.
  119.      * 
  120.      * @see #addChangeListener
  121.      * @see #createChangeListener
  122.      */
  123.     protected ChangeListener changeListener = createChangeListener();
  124.  
  125.    
  126.     /**
  127.      * Only one ChangeEvent is needed per slider instance since the
  128.      * event's only (read-only) state is the source property.  The source
  129.      * of events generated here is always "this". The event is lazily
  130.      * created the first time that an event notification is fired.
  131.      * 
  132.      * @see #fireStateChanged
  133.      */
  134.     protected transient ChangeEvent changeEvent = null;
  135.  
  136.  
  137.     private void checkOrientation(int orientation) {
  138.         switch (orientation) {
  139.         case VERTICAL:
  140.         case HORIZONTAL:
  141.             break;
  142.         default:
  143.             throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
  144.         }
  145.     }
  146.  
  147.  
  148.     /**
  149.      * Creates a horizontal slider with the range 0 to 100 and
  150.      * an intitial value of 50.
  151.      */
  152.     public JSlider() {
  153.         this(HORIZONTAL, 0, 100, 50);
  154.     }
  155.  
  156.  
  157.     /**
  158.      * Creates a slider using the specified orientation with the 
  159.      * range 0 to 100 and an intitial value of 50.
  160.      */
  161.     public JSlider(int orientation) {
  162.         this(orientation, 0, 100, 50);
  163.     }
  164.  
  165.  
  166.     /**
  167.      * Creates a horizontal slider using the specified min and max
  168.      * with an intitial value of 50.
  169.      */
  170.     public JSlider(int min, int max) {
  171.         this(HORIZONTAL, min, max, 50);
  172.     }
  173.  
  174.  
  175.     /**
  176.      * Creates a horizontal slider using the specified min, max and value.
  177.      */
  178.     public JSlider(int min, int max, int value) {
  179.         this(HORIZONTAL, min, max, value);
  180.     }
  181.  
  182.  
  183.     /**
  184.      * Creates a slider with the specified orientation and the
  185.      * specified mimimum, maximum, and initial values.
  186.      * 
  187.      * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
  188.      *
  189.      * @see #setOrientation
  190.      * @see #setMinimum
  191.      * @see #setMaximum
  192.      * @see #setValue
  193.      */
  194.     public JSlider(int orientation, int min, int max, int value) 
  195.     {
  196.         checkOrientation(orientation);
  197.         this.orientation = orientation;
  198.         sliderModel = new DefaultBoundedRangeModel(value, 0, min, max);
  199.         sliderModel.addChangeListener(changeListener);
  200.         updateUI();
  201.     }
  202.  
  203.  
  204.     /**
  205.      * Creates a horizontal slider using the specified
  206.      * BoundedRangeModel.
  207.      */
  208.     public JSlider(BoundedRangeModel brm) 
  209.     {
  210.         this.orientation = JSlider.HORIZONTAL;
  211.         setModel(brm);
  212.         sliderModel.addChangeListener(changeListener);
  213.         updateUI();
  214.     }
  215.  
  216.  
  217.     /**
  218.      * Gets the UI object which implements the L&F for this component.
  219.      *
  220.      * @return the SliderUI object that implements the Slider L&F
  221.      */
  222.     public SliderUI getUI() {
  223.         return (SliderUI)ui;
  224.     }
  225.  
  226.  
  227.     /**
  228.      * Sets the UI object which implements the L&F for this component.
  229.      *
  230.      * @param ui the SliderUI L&F object
  231.      * @see UIDefaults#getUI
  232.      * @beaninfo
  233.      *        bound: true
  234.      *       hidden: true
  235.      *    attribute: visualUpdate true
  236.      *  description: The UI object that implements the slider's LookAndFeel. 
  237.      */
  238.     public void setUI(SliderUI ui) {
  239.         super.setUI(ui);
  240.     }
  241.  
  242.  
  243.     /**
  244.      * Notification from the UIFactory that the L&F has changed. 
  245.      * Called to replace the UI with the latest version from the 
  246.      * default UIFactory.
  247.      *
  248.      * @see JComponent#updateUI
  249.      */
  250.     public void updateUI() {
  251.         updateLabelUIs();
  252.         setUI((SliderUI)UIManager.getUI(this));
  253.     }
  254.  
  255.  
  256.     /**
  257.      * Returns the name of the L&F class that renders this component.
  258.      *
  259.      * @return "SliderUI"
  260.      * @see JComponent#getUIClassID
  261.      * @see UIDefaults#getUI
  262.      */
  263.     public String getUIClassID() {
  264.         return uiClassID;
  265.     }
  266.  
  267.  
  268.     /**
  269.      * We pass Change events along to the listeners with the 
  270.      * the slider (instead of the model itself) as the event source.
  271.      */
  272.     private class ModelListener implements ChangeListener, Serializable {
  273.         public void stateChanged(ChangeEvent e) {
  274.             fireStateChanged();
  275.         }
  276.     }
  277.  
  278.  
  279.     /**
  280.      * Subclasses that want to handle model ChangeEvents differently
  281.      * can override this method to return their own ChangeListener 
  282.      * implementation.  The default ChangeListener just forwards 
  283.      * ChangeEvents to the ChangeListeners added directly to the slider.
  284.      * 
  285.      * @see #fireStateChanged
  286.      */
  287.     protected ChangeListener createChangeListener() {
  288.         return new ModelListener();
  289.     }
  290.  
  291.  
  292.     /**
  293.      * Adds a ChangeListener to the slider.
  294.      *
  295.      * @param l the ChangeListener to add
  296.      * @see #fireStateChanged
  297.      * @see #removeChangeListener
  298.      */
  299.     public void addChangeListener(ChangeListener l) {
  300.         listenerList.add(ChangeListener.class, l);
  301.     }
  302.     
  303.  
  304.     /**
  305.      * Removes a ChangeListener from the slider.
  306.      *
  307.      * @param l the ChangeListener to remove
  308.      * @see #fireStateChanged
  309.      * @see #addChangeListener
  310.  
  311.      */
  312.     public void removeChangeListener(ChangeListener l) {
  313.         listenerList.remove(ChangeListener.class, l);
  314.     }
  315.         
  316.  
  317.     /**
  318.      * Send a ChangeEvent, whose source is this Slider, to
  319.      * each listener.  This method method is called each time 
  320.      * a ChangeEvent is received from the model.
  321.      * 
  322.      * @see #addChangeListener
  323.      * @see EventListenerList
  324.      */
  325.     protected void fireStateChanged() {
  326.         Object[] listeners = listenerList.getListenerList();
  327.         for (int i = listeners.length - 2; i >= 0; i -= 2) {
  328.             if (listeners[i]==ChangeListener.class) {
  329.                 if (changeEvent == null) {
  330.                     changeEvent = new ChangeEvent(this);
  331.                 }
  332.                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  333.             }          
  334.         }
  335.     }   
  336.  
  337.  
  338.     /**
  339.      * Returns data model that handles the sliders three 
  340.      * fundamental properties: minimum, maximum, value.
  341.      * 
  342.      * @see #setModel
  343.      */
  344.     public BoundedRangeModel getModel() {
  345.         return sliderModel;
  346.     }
  347.  
  348.  
  349.     /**
  350.      * Sets the model that handles the sliders three 
  351.      * fundamental properties: minimum, maximum, value.
  352.      * 
  353.      * @see #getModel
  354.      * @beaninfo
  355.      *       bound: true
  356.      * description: The sliders BoundedRangeModel.
  357.      */
  358.     public void setModel(BoundedRangeModel newModel) 
  359.     {
  360.         BoundedRangeModel oldModel = getModel();
  361.  
  362.         if (oldModel != null) {
  363.             oldModel.removeChangeListener(changeListener);
  364.         }
  365.  
  366.         sliderModel = newModel;
  367.  
  368.         if (newModel != null) {
  369.             newModel.addChangeListener(changeListener);
  370.  
  371.             if (accessibleContext != null) {
  372.                 accessibleContext.firePropertyChange(
  373.                         AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  374.                         (oldModel == null 
  375.                          ? null : new Integer(oldModel.getValue())),
  376.                         (newModel == null 
  377.                          ? null : new Integer(newModel.getValue())));
  378.             }
  379.         }
  380.  
  381.         firePropertyChange("model", oldModel, sliderModel);
  382.     }
  383.  
  384.  
  385.     /**
  386.      * Returns the sliders value.
  387.      * @return the models value property
  388.      * @see #setValue
  389.      */
  390.     public int getValue() { 
  391.         return getModel().getValue(); 
  392.     }
  393.  
  394.  
  395.     /**
  396.      * Sets the sliders current value.  This method just forwards
  397.      * the value to the model.
  398.      * 
  399.      * @see #getValue
  400.      * @beaninfo
  401.      *   preferred: true
  402.      * description: The sliders current value.
  403.      */
  404.     public void setValue(int n) { 
  405.         BoundedRangeModel m = getModel();
  406.         int oldValue = m.getValue();
  407.         m.setValue(n);
  408.  
  409.         if (accessibleContext != null) {
  410.             accessibleContext.firePropertyChange(
  411.                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  412.                     new Integer(oldValue),
  413.                     new Integer(m.getValue()));
  414.         }
  415.     }
  416.  
  417.  
  418.     /**
  419.      * Returns the minimum value supported by the slider. 
  420.      *
  421.      * @return the value of the models minimum property
  422.      * @see #setMinimum
  423.      */
  424.     public int getMinimum() { 
  425.         return getModel().getMinimum(); 
  426.     }
  427.  
  428.  
  429.     /**
  430.      * Sets the models minimum property.
  431.      *
  432.      * @see #getMinimum
  433.      * @see BoundedRangeModel#setMinimum
  434.      * @beaninfo
  435.      *   preferred: true
  436.      * description: The sliders minimum value.
  437.      */
  438.     public void setMinimum(int minimum) { 
  439.         int oldMin = getModel().getMinimum();
  440.         getModel().setMinimum(minimum); 
  441.     firePropertyChange( "minimum", new Integer( oldMin ), new Integer( minimum ) );
  442.     }
  443.  
  444.  
  445.     /**
  446.      * Returns the maximum value supported by the slider.
  447.      *
  448.      * @return the value of the models maximum property
  449.      * @see #setMaximum
  450.      */
  451.     public int getMaximum() { 
  452.         return getModel().getMaximum(); 
  453.     }
  454.  
  455.  
  456.     /**
  457.      * Sets the models maximum property.  
  458.      * 
  459.      * @see #getMaximum
  460.      * @see BoundedRangeModel#setMaximum
  461.      * @beaninfo
  462.      *   preferred: true
  463.      * description: The sliders maximum value.
  464.      */
  465.     public void setMaximum(int maximum) { 
  466.         int oldMax = getModel().getMaximum();
  467.         getModel().setMaximum(maximum); 
  468.     firePropertyChange( "maximum", new Integer( oldMax ), new Integer( maximum ) );
  469.     }
  470.  
  471.  
  472.     /**
  473.      * True if the slider knob is being dragged.
  474.      * 
  475.      * @return the value of the models valueIsAdjusting property
  476.      * @see #setValueIsAdjusting
  477.      */
  478.     public boolean getValueIsAdjusting() { 
  479.         return getModel().getValueIsAdjusting(); 
  480.     }
  481.  
  482.  
  483.     /**
  484.      * Sets the models valueIsAdjusting property.  Slider look and
  485.      * feel implementations should set this property to true when 
  486.      * a knob drag begins, and to false when the drag ends.  The
  487.      * slider model will not generate ChangeEvents while
  488.      * valueIsAdjusting is true.
  489.      * 
  490.      * @see #getValueIsAdjusting
  491.      * @see BoundedRangeModel#setValueIsAdjusting
  492.      * @beaninfo
  493.      *      expert: true
  494.      * description: True if the slider knob is being dragged.
  495.      */
  496.     public void setValueIsAdjusting(boolean b) { 
  497.         BoundedRangeModel m = getModel();   
  498.         boolean oldValue = m.getValueIsAdjusting();
  499.         m.setValueIsAdjusting(b);
  500.    
  501.         if ((oldValue != b) && (accessibleContext != null)) {
  502.             accessibleContext.firePropertyChange(
  503.                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  504.                     ((oldValue) ? AccessibleState.BUSY : null),
  505.                     ((b) ? AccessibleState.BUSY : null));
  506.         }
  507.     }
  508.  
  509.  
  510.     /**
  511.      * Returns the "extent" -- the range of values "covered" by the knob.
  512.      * @return an int representing the extent
  513.      * @see #setExtent
  514.      * @see BoundedRangeModel#getExtent
  515.      */
  516.     public int getExtent() { 
  517.         return getModel().getExtent(); 
  518.     }
  519.  
  520.  
  521.     /**
  522.      * Sets the size of the range "covered" by the knob.  Most look
  523.      * and feel implementations will change the value by this amount
  524.      * if the user clicks on either side of the knob.
  525.      * 
  526.      * @see #getExtent
  527.      * @see BoundedRangeModel#setExtent
  528.      * @beaninfo
  529.      *      expert: true
  530.      * description: Size of the range covered by the knob.
  531.      */
  532.     public void setExtent(int extent) { 
  533.         getModel().setExtent(extent); 
  534.     }
  535.  
  536.  
  537.     /**
  538.      * Return this slider's vertical or horizontal orientation.
  539.      * @return VERTICAL or HORIZONTAL
  540.      * @see #setOrientation
  541.      */
  542.     public int getOrientation() { 
  543.         return orientation; 
  544.     }
  545.  
  546.  
  547.     /**
  548.      * Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
  549.      * 
  550.      * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
  551.      * @see #getOrientation
  552.      * @beaninfo
  553.      *    preferred: true
  554.      *        bound: true
  555.      *    attribute: visualUpdate true
  556.      *  description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
  557.      *         enum: VERTICAL JSlider.VERTICAL 
  558.      *               HORIZONTAL JSlider.HORIZONTAL
  559.      * 
  560.      */
  561.     public void setOrientation(int orientation) 
  562.     { 
  563.         checkOrientation(orientation);
  564.         int oldValue = this.orientation;
  565.         this.orientation = orientation;
  566.         firePropertyChange("orientation", oldValue, orientation);
  567.  
  568.         if ((oldValue != orientation) && (accessibleContext != null)) {
  569.             accessibleContext.firePropertyChange(
  570.                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  571.                     ((oldValue == VERTICAL) 
  572.                      ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
  573.                     ((orientation == VERTICAL) 
  574.                      ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
  575.         }
  576.         if (orientation != oldValue) {
  577.             revalidate();
  578.         }
  579.     }
  580.  
  581.  
  582.  
  583.     /**
  584.      * Returns the dictionary of what labels to draw at which values.
  585.      *
  586.      * @return the Dictionary containing labels and where to draw them
  587.      */
  588.     public Dictionary getLabelTable() {
  589. /*
  590.         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
  591.             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  592.         }
  593. */
  594.         return labelTable;
  595.     }
  596.  
  597.  
  598.     /**
  599.      * Used to specify what label will be drawn at any given value.
  600.      * The key-value pairs are of this format: <B>{ Integer value, java.awt.Component label }</B>
  601.      *
  602.      * @see #createStandardLabels
  603.      * @see #getLabelTable
  604.      * @beaninfo
  605.      *       hidden: true
  606.      *        bound: true
  607.      *    attribute: visualUpdate true
  608.      *  description: Specifies what labels will be drawn for any given value.
  609.      */
  610.     public void setLabelTable( Dictionary labels ) {
  611.         Dictionary oldTable = labelTable;
  612.         labelTable = labels;
  613.         updateLabelUIs();
  614.         firePropertyChange("labelTable", oldTable, labelTable );
  615.         if (labels != oldTable) {
  616.             revalidate();
  617.             repaint();
  618.         }
  619.     }
  620.  
  621.  
  622.     /**
  623.      * Called internally to replace the label UIs with the latest versions
  624.      * from the UIFactory when the UIFactory notifies us via
  625.      * <code>updateUI</code> that the L&F has changed.
  626.      *
  627.      * @see JComponent#updateUI
  628.      */
  629.     protected void updateLabelUIs() {
  630.         if ( getLabelTable() == null ) {
  631.             return;
  632.         }
  633.         Enumeration labels = getLabelTable().keys();
  634.         while ( labels.hasMoreElements() ) {
  635.             Object value = getLabelTable().get( labels.nextElement() );
  636.             if ( value instanceof JComponent ) {
  637.                 JComponent component = (JComponent)value;
  638.                 component.updateUI();
  639.                 component.setSize( component.getPreferredSize()  );
  640.             }
  641.         }
  642.     }
  643.  
  644.  
  645.     /**
  646.      * Creates a hashtable that will draw text labels starting at the slider minimum using the
  647.      * increment specified. If you call createStandardLabels( 10 ) and the slider minimum is
  648.      * zero, then it will make labels for the values 0, 10, 20, 30, and so on.
  649.      * @see #setLabelTable
  650.      */
  651.     public Hashtable createStandardLabels( int increment ) {
  652.         return createStandardLabels( increment, getMinimum() );
  653.     }
  654.  
  655.  
  656.     /**
  657.      * Creates a hashtable that will draw text labels starting at the start point
  658.      * specified using the increment specified. If you call createStandardLabels( 10, 2 ),
  659.      * then it will make labels for the values 2, 12, 22, 32, and so on.
  660.      * @see #setLabelTable
  661.      */
  662.     public Hashtable createStandardLabels( int increment, int start ) {
  663.         if ( start > getMaximum() || start < getMinimum() ) {
  664.             throw new IllegalArgumentException( "Slider label start point out of range." );
  665.         }
  666.     
  667.     class SmartHashtable extends Hashtable implements PropertyChangeListener {
  668.         int increment = 0;
  669.         int start = 0;
  670.         boolean startAtMin = false;
  671.  
  672.         class LabelUIResource extends JLabel implements UIResource {
  673.             public LabelUIResource( String text, int alignment ) {
  674.             super( text, alignment );
  675.         }
  676.         }
  677.       
  678.         public SmartHashtable( int increment, int start ) {
  679.             super();
  680.         this.increment = increment;
  681.             this.start = start;
  682.         startAtMin = start == getMinimum();
  683.             createLabels();
  684.         }
  685.  
  686.         public void propertyChange( PropertyChangeEvent e ) {
  687.             if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
  688.             start = getMinimum();
  689.         }
  690.  
  691.             if ( e.getPropertyName().equals( "minimum" ) ||
  692.              e.getPropertyName().equals( "maximum" ) ) {
  693.  
  694.           Enumeration keys = getLabelTable().keys();
  695.             Object key = null;
  696.             Hashtable hashtable = new Hashtable();
  697.  
  698.             // Save the labels that were added by the developer
  699.             while ( keys.hasMoreElements() ) {
  700.                 key = keys.nextElement();
  701.             Object value = getLabelTable().get( key );
  702.                 if ( !(value instanceof LabelUIResource) ) {
  703.                 hashtable.put( key, value );
  704.             }
  705.             }
  706.             
  707.             clear();
  708.             createLabels();
  709.  
  710.             // Add the saved labels
  711.             keys = hashtable.keys();
  712.             while ( keys.hasMoreElements() ) {
  713.                 key = keys.nextElement();
  714.             put( key, hashtable.get( key ) );
  715.             }
  716.  
  717.             ((JSlider)e.getSource()).setLabelTable( this );
  718.         }
  719.         }
  720.  
  721.         void createLabels() {
  722.             for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
  723.             put( new Integer( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
  724.         }
  725.         }
  726.     }
  727.  
  728.         SmartHashtable table = new SmartHashtable( increment, start );
  729.  
  730.     if ( getLabelTable() != null && (getLabelTable() instanceof PropertyChangeListener) ) {
  731.         removePropertyChangeListener( (PropertyChangeListener)getLabelTable() );
  732.     }
  733.  
  734.     addPropertyChangeListener( table );
  735.  
  736.         return table;
  737.     }
  738.  
  739.  
  740.     /**
  741.      * Returns true if the value-range shown for the slider is reversed,
  742.      * with the maximum value at the left end of a horizontal slider or
  743.      * at the bottom of a vertical one.
  744.      *
  745.      * @return true if the slider values are reversed from their normal order
  746.      */
  747.     public boolean getInverted() { 
  748.         return isInverted; 
  749.     }
  750.     
  751.  
  752.     /**
  753.      * Specify true to reverse the value-range shown for the slider so that
  754.      * the maximum value is at the left end of a horizontal slider or
  755.      * at the bottom of a vertical one. Specify false to put the value range
  756.      * in the normal order.
  757.      *
  758.      * @param b  true to reverse the slider values from their normal order
  759.      * @beaninfo
  760.      *        bound: true
  761.      *    attribute: visualUpdate true
  762.      *  description: If true reverses the slider values from their normal order 
  763.      * 
  764.      */
  765.     public void setInverted( boolean b ) { 
  766.         boolean oldValue = isInverted;
  767.         isInverted = b; 
  768.         firePropertyChange("inverted", oldValue, isInverted);
  769.         if (b != oldValue) {
  770.             repaint();
  771.         }
  772.     }
  773.  
  774.  
  775.     /**
  776.      * This method returns the major tick spacing.  The number that is returned
  777.      * represents the distance, measured in values, between each major tick mark.
  778.      * If you have a slider with a range from 0 to 50 and the major tick spacing
  779.      * is set to 10, you will get major ticks next to the following values:
  780.      * 0, 10, 20, 30, 40, 50.
  781.      *
  782.      * @return the number of values between major ticks
  783.      * @see #setMajorTickSpacing
  784.      */
  785.     public int getMajorTickSpacing() { 
  786.         return majorTickSpacing; 
  787.     }
  788.  
  789.  
  790.     /**
  791.      * This method sets the major tick spacing.  The number that is passed-in
  792.      * represents the distance, measured in values, between each major tick mark.
  793.      * If you have a slider with a range from 0 to 50 and the major tick spacing
  794.      * is set to 10, you will get major ticks next to the following values:
  795.      * 0, 10, 20, 30, 40, 50.
  796.      *
  797.      * @see #getMajorTickSpacing
  798.      * @beaninfo
  799.      *        bound: true
  800.      *    attribute: visualUpdate true
  801.      *  description: Sets the number of values between major tick marks.
  802.      * 
  803.      */
  804.     public void setMajorTickSpacing(int n) {
  805.         int oldValue = majorTickSpacing;
  806.         majorTickSpacing = n;
  807.         if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) {
  808.             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  809.         }
  810.         firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing);
  811.         if (majorTickSpacing != oldValue && getPaintTicks()) {
  812.             repaint();
  813.         }
  814.     }
  815.  
  816.  
  817.     
  818.     /**
  819.      * This method returns the minor tick spacing.  The number that is returned
  820.      * represents the distance, measured in values, between each minor tick mark.
  821.      * If you have a slider with a range from 0 to 50 and the minor tick spacing
  822.      * is set to 10, you will get minor ticks next to the following values:
  823.      * 0, 10, 20, 30, 40, 50.
  824.      *
  825.      * @return the number of values between minor ticks
  826.      * @see #getMinorTickSpacing
  827.      */
  828.     public int getMinorTickSpacing() { 
  829.         return minorTickSpacing; 
  830.     }
  831.  
  832.  
  833.     /**
  834.      * This method sets the minor tick spacing.  The number that is passed-in
  835.      * represents the distance, measured in values, between each minor tick mark.
  836.      * If you have a slider with a range from 0 to 50 and the minor tick spacing
  837.      * is set to 10, you will get minor ticks next to the following values:
  838.      * 0, 10, 20, 30, 40, 50.
  839.      *
  840.      * @see #getMinorTickSpacing
  841.      * @beaninfo
  842.      *        bound: true
  843.      *    attribute: visualUpdate true
  844.      *  description: Sets the number of values between minor tick marks.
  845.      */
  846.     public void setMinorTickSpacing(int n) { 
  847.         int oldValue = minorTickSpacing;
  848.         minorTickSpacing = n; 
  849.         firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing);
  850.         if (minorTickSpacing != oldValue && getPaintTicks()) {
  851.             repaint();
  852.         }
  853.     }
  854.  
  855.  
  856.     /**
  857.      * Returns true if the knob (and the data value it represents) 
  858.      * resolve to the closest tick mark next to where the user
  859.      * positioned the knob.
  860.      *
  861.      * @return true if the value snaps to the nearest tick mark, else false
  862.      * @see #setSnapToTicks
  863.      */
  864.     public boolean getSnapToTicks() { 
  865.         return snapToTicks; 
  866.     }
  867.  
  868.  
  869.     /**
  870.      * Returns true if the knob (and the data value it represents) 
  871.      * resolve to the closest slider value next to where the user
  872.      * positioned the knob.
  873.      *
  874.      * @return true if the value snaps to the nearest slider value, else false
  875.      * @see #setSnapToValue
  876.      */
  877.     boolean getSnapToValue() { 
  878.         return snapToValue; 
  879.     }
  880.  
  881.  
  882.     /**
  883.      * Specifying true makes the knob (and the data value it represents) 
  884.      * resolve to the closest tick mark next to where the user
  885.      * positioned the knob.
  886.      *
  887.      * @param b  true to snap the knob to the nearest tick mark
  888.      * @see #getSnapToTicks
  889.      * @beaninfo
  890.      *       bound: true
  891.      * description: If true snap the knob to the nearest tick mark.
  892.      */
  893.     public void setSnapToTicks(boolean b) { 
  894.         boolean oldValue = snapToTicks;
  895.         snapToTicks = b; 
  896.         firePropertyChange("snapToTicks", oldValue, snapToTicks);
  897.     }
  898.  
  899.  
  900.     /**
  901.      * Specifying true makes the knob (and the data value it represents) 
  902.      * resolve to the closest slider value next to where the user
  903.      * positioned the knob. If the snapToTicks property has been set to
  904.      * true, the snap-to-ticks behavior will prevail.
  905.      *
  906.      * @param b  true to snap the knob to the nearest slider value
  907.      * @see #getSnapToValue
  908.      * @see #setSnapToTicks
  909.      * @beaninfo
  910.      *       bound: true
  911.      * description: If true snap the knob to the nearest slider value.
  912.      */
  913.     void setSnapToValue(boolean b) { 
  914.         boolean oldValue = snapToValue;
  915.         snapToValue = b; 
  916.         firePropertyChange("snapToValue", oldValue, snapToValue);
  917.     }
  918.  
  919.  
  920.     /**
  921.      * Tells if tick marks are to be painted.
  922.      * @return true if tick marks are painted, else false
  923.      * @see #setPaintTicks
  924.      */
  925.     public boolean getPaintTicks() { 
  926.         return paintTicks; 
  927.     }
  928.  
  929.  
  930.     /**
  931.      * Determines whether tick marks are painted on the slider.
  932.      * @see #getPaintTicks
  933.      * @beaninfo
  934.      *        bound: true
  935.      *    attribute: visualUpdate true
  936.      *  description: If true tick marks are painted on the slider.
  937.      */
  938.     public void setPaintTicks(boolean b) { 
  939.         boolean oldValue = paintTicks;
  940.         paintTicks = b;
  941.         firePropertyChange("paintTicks", oldValue, paintTicks);
  942.         if (paintTicks != oldValue) {
  943.             revalidate();
  944.             repaint();
  945.         }
  946.     }
  947.  
  948.     /**
  949.      * Tells if the track (area the slider slides in) is to be painted.
  950.      * @return true if track is painted, else false
  951.      * @see #setPaintTrack
  952.      */
  953.     public boolean getPaintTrack() { 
  954.         return paintTrack; 
  955.     }
  956.  
  957.  
  958.     /**
  959.      * Determines whether the track is painted on the slider.
  960.      * @see #getPaintTrack
  961.      * @beaninfo
  962.      *        bound: true
  963.      *    attribute: visualUpdate true
  964.      *  description: If true, the track is painted on the slider.
  965.      */
  966.     public void setPaintTrack(boolean b) { 
  967.         boolean oldValue = paintTrack;
  968.         paintTrack = b;
  969.         firePropertyChange("paintTrack", oldValue, paintTrack);
  970.         if (paintTrack != oldValue) {
  971.             repaint();
  972.         }
  973.     }
  974.  
  975.  
  976.     /**
  977.      * Tells if labels are to be painted.
  978.      * @return true if labels are painted, else false
  979.      * @see #setPaintLabels
  980.      */
  981.     public boolean getPaintLabels() { 
  982.         return paintLabels; 
  983.     }
  984.  
  985.     
  986.     /**
  987.      * Determines whether labels are painted on the slider.
  988.      * @see #getPaintLabels
  989.      * @beaninfo
  990.      *        bound: true
  991.      *    attribute: visualUpdate true
  992.      *  description: If true labels are painted on the slider.
  993.      */
  994.     public void setPaintLabels(boolean b) {
  995.         boolean oldValue = paintLabels;
  996.         paintLabels = b;
  997.         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
  998.             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
  999.         }
  1000.         firePropertyChange("paintLabels", oldValue, paintLabels);
  1001.         if (paintLabels != oldValue) {
  1002.             revalidate();
  1003.             repaint();
  1004.         }
  1005.     }   
  1006.  
  1007.  
  1008.     /** 
  1009.      * See readObject() and writeObject() in JComponent for more 
  1010.      * information about serialization in Swing.
  1011.      */
  1012.     private void writeObject(ObjectOutputStream s) throws IOException {
  1013.         s.defaultWriteObject();
  1014.     if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  1015.         ui.installUI(this);
  1016.     }
  1017.     }
  1018.  
  1019.  
  1020.     /**
  1021.      * Returns a string representation of this JSlider. This method 
  1022.      * is intended to be used only for debugging purposes, and the 
  1023.      * content and format of the returned string may vary between      
  1024.      * implementations. The returned string may be empty but may not 
  1025.      * be <code>null</code>.
  1026.      * <P>
  1027.      * Overriding paramString() to provide information about the
  1028.      * specific new aspects of the JFC components.
  1029.      * 
  1030.      * @return  a string representation of this JSlider.
  1031.      */
  1032.     protected String paramString() {
  1033.     String paintTicksString = (paintTicks ?
  1034.                    "true" : "false");
  1035.     String paintTrackString = (paintTrack ?
  1036.                    "true" : "false");
  1037.     String paintLabelsString = (paintLabels ?
  1038.                     "true" : "false");
  1039.     String isInvertedString = (isInverted ?
  1040.                    "true" : "false");
  1041.     String snapToTicksString = (snapToTicks ?
  1042.                     "true" : "false");
  1043.     String snapToValueString = (snapToValue ?
  1044.                     "true" : "false");
  1045.     String orientationString = (orientation == HORIZONTAL ?
  1046.                     "HORIZONTAL" : "VERTICAL");
  1047.  
  1048.     return super.paramString() +
  1049.     ",isInverted=" + isInvertedString +
  1050.     ",majorTickSpacing=" + majorTickSpacing +
  1051.     ",minorTickSpacing=" + minorTickSpacing +
  1052.     ",orientation=" + orientationString +
  1053.     ",paintLabels=" + paintLabelsString +
  1054.     ",paintTicks=" + paintTicksString +
  1055.     ",paintTrack=" + paintTrackString +
  1056.     ",snapToTicks=" + snapToTicksString +
  1057.     ",snapToValue=" + snapToValueString;
  1058.     }
  1059.  
  1060.  
  1061. /////////////////
  1062. // Accessibility support
  1063. ////////////////
  1064.  
  1065.     /**
  1066.      * Get the AccessibleContext associated with this JComponent
  1067.      *
  1068.      * @return the AccessibleContext of this JComponent
  1069.      */
  1070.     public AccessibleContext getAccessibleContext() {
  1071.         if (accessibleContext == null) {
  1072.             accessibleContext = new AccessibleJSlider();
  1073.         }
  1074.         return accessibleContext;
  1075.     }
  1076.  
  1077.     /**
  1078.      * The class used to obtain the accessible role for this object.
  1079.      * <p>
  1080.      * <strong>Warning:</strong>
  1081.      * Serialized objects of this class will not be compatible with
  1082.      * future Swing releases.  The current serialization support is appropriate
  1083.      * for short term storage or RMI between applications running the same
  1084.      * version of Swing.  A future release of Swing will provide support for
  1085.      * long term persistence.
  1086.      */
  1087.     protected class AccessibleJSlider extends AccessibleJComponent
  1088.         implements AccessibleValue {
  1089.  
  1090.         /**
  1091.          * Get the state set of this object.
  1092.          *
  1093.          * @return an instance of AccessibleState containing the current state 
  1094.          * of the object
  1095.          * @see AccessibleState
  1096.          */
  1097.         public AccessibleStateSet getAccessibleStateSet() {
  1098.             AccessibleStateSet states = super.getAccessibleStateSet();
  1099.             if (getValueIsAdjusting()) {
  1100.                 states.add(AccessibleState.BUSY);
  1101.             }
  1102.             if (getOrientation() == VERTICAL) {
  1103.                 states.add(AccessibleState.VERTICAL);
  1104.             } else {
  1105.                 states.add(AccessibleState.HORIZONTAL);
  1106.             }
  1107.             return states;
  1108.         }
  1109.  
  1110.         /**
  1111.          * Get the role of this object.
  1112.          *
  1113.          * @return an instance of AccessibleRole describing the role of the object
  1114.          */
  1115.         public AccessibleRole getAccessibleRole() {
  1116.             return AccessibleRole.SLIDER;
  1117.         }
  1118.  
  1119.         /**
  1120.          * Get the AccessibleValue associated with this object if one
  1121.          * exists.  Otherwise return null.
  1122.          */
  1123.         public AccessibleValue getAccessibleValue() {
  1124.             return this;
  1125.         }
  1126.  
  1127.         /**
  1128.          * Get the accessible value of this object.
  1129.          *
  1130.          * @return The current value of this object.
  1131.          */
  1132.         public Number getCurrentAccessibleValue() {
  1133.             return new Integer(getValue());
  1134.         }
  1135.  
  1136.         /**
  1137.          * Set the value of this object as a Number.
  1138.          *
  1139.          * @return True if the value was set.
  1140.          */
  1141.         public boolean setCurrentAccessibleValue(Number n) {
  1142.             if (n instanceof Integer) {
  1143.                 setValue(n.intValue());
  1144.                 return true;
  1145.             } else {
  1146.                 return false;
  1147.             }
  1148.         }
  1149.  
  1150.         /**
  1151.          * Get the minimum accessible value of this object.
  1152.          *
  1153.          * @return The minimum value of this object.
  1154.          */
  1155.         public Number getMinimumAccessibleValue() {
  1156.             return new Integer(getMinimum());
  1157.         }
  1158.  
  1159.         /**
  1160.          * Get the maximum accessible value of this object.
  1161.          *
  1162.          * @return The maximum value of this object.
  1163.          */
  1164.         public Number getMaximumAccessibleValue() {
  1165.             return new Integer(getMaximum());
  1166.         }
  1167.     } // AccessibleJSlider
  1168. }
  1169.